package com.eric.utils;

import lombok.SneakyThrows;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;

import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.util.*;

/**
 * @description: 数据脱敏工具类
 * @author: liuBing
 * @create: 2024-03-13 10:36
 **/
public class DataDesensitizeHandler {

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<>();
        map.put("id", "md5");
        map.put("name", "name");
        map.put("phone", "phone");
        desensitizeCSVColumns("/Users/liubing/data/csv/test_1.csv", "/Users/liubing/data/csv/test_host_des_1.csv", map);

        System.out.println(Arrays.toString(getCsvHeaderList("/Users/liubing/data/csv/test_1.csv")));
    }

    /**
     * 对CSV文件中的敏感列进行脱敏处理。
     *
     * @param inputFilePath  输入CSV文件的路径
     * @param outputFilePath 输出CSV文件的路径
     * @param sensitiveColumnsMap 敏感列映射表，key为原始列名，value为脱敏后列名7
     */
    @SneakyThrows
    private static void desensitizeCSVColumns(String inputFilePath, String outputFilePath, Map<String, String> sensitiveColumnsMap) {
        // 读取CSV文件
        FileReader reader = new FileReader(inputFilePath);
        CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withHeader());

        // 创建输出CSV文件并写入表头
        FileWriter writer = new FileWriter(outputFilePath);
        CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.withHeader(csvParser.getHeaderMap().keySet().toArray(new String[0])));

        // 遍历CSV文件的每一行，对敏感列进行脱敏处理后写入输出文件
        for (CSVRecord record : csvParser) {
            Collection<String> values = desensitizeRecord(record, sensitiveColumnsMap);
            csvPrinter.printRecord(values);
        }

        // 清理资源
        csvPrinter.flush();
        csvPrinter.close();
        csvParser.close();
    }

    private static Collection<String> desensitizeRecord(CSVRecord record, Map<String, String> sensitiveColumnsMap) {
        Map<String, String> map = new LinkedHashMap<>(record.toMap());
        for (Map.Entry<String, String> sensitiveColumns : sensitiveColumnsMap.entrySet()) {
            String columnName = sensitiveColumns.getKey();
            String desensitizeType = sensitiveColumns.getValue();

            String originalValue = record.get(columnName);
            String desensitizedValue = desensitizeField(originalValue, desensitizeType);
            map.put(columnName, desensitizedValue);
        }
        return map.values();
    }


    private static String desensitizeField(String originalValue, String desensitizeType) {
        switch (desensitizeType) {
//            case "hash":
//                return "*" + originalValue.substring(1);
//            case "sm3":
//                return "*****@" + originalValue.split("@")[1];
            case "md5":
                return encrypt(originalValue, "MD5");
            case "sha256":
                return encrypt(originalValue, "SHA-256");

            case "phone":
                return originalValue.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2");
            case "id_number":
                return originalValue.replaceAll("(\\d)\\d+(\\d{2})", "$1***************$2");
            case "name":
                return originalValue.replaceAll("(\\S)(\\S*)", "$1**");
            case "address":
                return originalValue.replaceAll("([\\s\\S]{8})([\\s\\S]*)", "$1********$2");
            case "mail":
                return originalValue.replaceAll("([\\s\\S]{1,})@([\\s\\S]*)", "$1******@$2");
            case "bank_number":
                return originalValue.replaceAll("(\\d{4})\\d+(\\d{4})", "$1 **** **** $2");
            default:
                return originalValue;
        }
    }

    @SneakyThrows
    private static String encrypt(String input, String algorithmType) {
        MessageDigest md = MessageDigest.getInstance(algorithmType);
        byte[] messageDigest = md.digest(input.getBytes());
        BigInteger no = new BigInteger(1, messageDigest);
        return no.toString(16);
    }

    /**
     * 获取 csv 的字段行
     */
    @SneakyThrows
    public static String[] getCsvHeaderList(String inputFilePath) {
        FileReader reader = new FileReader(inputFilePath);
        CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withHeader());
        return csvParser.getHeaderMap().keySet().toArray(new String[0]);
    }
    @SneakyThrows
    public static String[] getCsvHeaderList(File file) {
        FileReader reader = new FileReader(file);
        CSVParser csvParser = new CSVParser(reader, CSVFormat.DEFAULT.withHeader());
        return csvParser.getHeaderMap().keySet().toArray(new String[0]);
    }
}
